package tcp

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"lib/network"
	"lib/structs/base"
	"lib/structs/enum"
	"net"
	"runtime"
	"sync"
	"time"
)

type Client struct {
	Uid       string
	Conn      net.Conn
	inChan    chan base.AmsResponse
	outChan   chan base.ClientInstruct
	closeChan chan byte
	mutex     sync.Mutex
	IsClosed  bool
	tcpServer *Server
}

func (c *Client) handMsg() {
	for {
		in, err := c.ReaderMessage()
		if err != nil {
			break
		}
		switch in.ResultType {
		case enum.Ping:
			continue
		case enum.Online:
			c.online(in.Result)
		case enum.SayHi:
			err = c.sayHi(in)
		case enum.CloudApps:
			err = c.saveAppList(in)
		case enum.WinSessionChange:
			err = c.handleSessionChange(in)
		case enum.CreateRdpWinAccount:
			continue
		default:
			err = errors.New(fmt.Sprintf("未知消息：%+v", in))
		}
		if err != nil {
			logrus.Errorf("处理客户端消息时发生错误：%s", err.Error())
		}
	}
}

func (c *Client) online(uid string) {
	defer c.tcpServer.clientMutex.Unlock()
	c.tcpServer.clientMutex.Lock()
	c.Uid = uid
	c.tcpServer.clientMap[uid] = c
}

func (c *Client) ReaderMessage() (msg base.AmsResponse, err error) {
	select {
	case msg = <-c.inChan:
	case <-c.closeChan:
		err = errors.New("connection is closed")
	}
	return
}
func (c *Client) WriteMessage(msg base.ClientInstruct) (err error) {
	msg.ServeTime = time.Now().Unix()
	select {
	case c.outChan <- msg:
	case <-c.closeChan:
		err = errors.New("connection is closed")
	}
	return
}

func (c *Client) readLoop() {
	var (
		bs  []byte
		err error
	)
	for {
		if bs, err = network.Decode(c.Conn); err != nil {
			goto ERR
		}
		inst := base.AmsResponse{}
		err = json.Unmarshal(bs, &inst)
		if err != nil {
			logrus.Errorf("读取到不合法的消息：%s", string(bs))
			goto ERR
		}
		select {
		case c.inChan <- inst:
		case <-c.closeChan:
			goto ERR
		}
	}
	// 发生错误时应该退出循环，否则协程无法正常回收
ERR:
	c.Close()
}

func (c *Client) writeLoop() {
	for {
		select {
		case msg := <-c.outChan:
			bs, err := network.Encode(msg)
			if err != nil {
				logrus.Errorf("tcp消息【%+v】编码错误,err:%v", msg, err)
				goto ERR
			}
			_, err = c.Conn.Write(bs)
			if err != nil {
				goto ERR
			}
		case <-c.closeChan:
			goto ERR
		}

	}
ERR:
	c.Close()
}

func (c *Client) Close() {
	defer c.mutex.Unlock()
	c.mutex.Lock()
	// 关闭操作只能执行一次
	if c.Conn != nil {
		_ = c.Conn.Close()
	}
	if !c.IsClosed {
		logrus.Debugf("客户端下线：%+v", c)
		close(c.inChan)
		close(c.outChan)
		close(c.closeChan)
		c.IsClosed = true
	}
	delete(c.tcpServer.clientMap, c.Uid)
	// 通知协程退出
	runtime.Goexit()
}
